package es

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
)

// Represents a connection with the ElasticSearch process
type Conn interface {
	Open(string, string) Index
}

// This is used to generate an id for any object in the index search.
// See DefaultGenerator for more information about how how the default works
type IdGenerator func(v interface{}) string

// Used to write/read information from the index.
type Index interface {
	// Allow the user to redefine how the Id generation works
	IdGen(IdGenerator)

	// Store the information with the given id inside the index.
	// If the second parameter isn't a string call json.Marshal on it. Otherwise just send the parameter to the server
	Write(string, interface{}) error

	// Do a range query on the given field.
	// The semantics of the search depends on how the field was indexed.
	//Range(string, interface{}, interface{}) Map

	// Do a term query on the given field.
	// The semantics of the search depends on how the field was indexed.
	Term(string, interface{}) (<-chan string, error)

	// Do a range query on the given field.
	// The semantics of the search depends on how the field was indexed.
	Range(string, interface{}, interface{}) (<-chan string, error)
}

type Map map[string]interface{}

func CastMap(v interface{}) Map {
	return Map(v.(map[string]interface{}))
}

func (m Map) AsMap(k string) Map {
	return m[k].(Map)
}

func (m Map) Set(k string, value interface{}) Map {
	m[k] = value
	return m
}

func (m Map) Map(k string) Map {
	if v, has := m[k]; has {
		return Map(v.(map[string]interface{}))
	}

	ret := make(Map)
	m[k] = ret
	return ret
}

func (m Map) String() string {
	buff, err := json.Marshal(m)
	if err != nil {
		return fmt.Sprintf("Error: %q", err)
	}
	return string(buff)
}

func FromJson(buff io.Reader) (Map, error) {
	m := make(Map)
	byteBuff, err := ioutil.ReadAll(buff)
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(byteBuff, &m)
	return m, err
}
